package com.jike.shop.cloud.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.gson.Gson;
import com.jike.shop.cloud.IPayService;
import com.jike.shop.cloud.entity.OrderInfo;
import com.jike.shop.cloud.entity.OrderPayInfo;
import com.jike.shop.cloud.entity.OrderProduct;
import com.jike.shop.cloud.entity.TransactionLog;
import com.jike.shop.cloud.enums.OrderPayStatusEnum;
import com.jike.shop.cloud.enums.OrderStatusChangeEventEnum;
import com.jike.shop.cloud.enums.OrderStatusEnum;
import com.jike.shop.cloud.mapper.OrderInfoMapper;
import com.jike.shop.cloud.mapper.OrderPayInfoMapper;
import com.jike.shop.cloud.mapper.OrderProductMapper;
import com.jike.shop.cloud.mapper.TransactionLogMapper;
import com.jike.shop.cloud.mq.producer.RocketMQProducer;
import com.jike.shop.cloud.service.OrderInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jike.shop.cloud.service.OrderProductService;
import com.jike.shop.common.utils.SnowFlakeGenerateIdWorker;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.persist.StateMachinePersister;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
import java.util.stream.Collectors;


/**
 * <p>
 * 父订单主表 服务实现类
 * </p>
 *
 * @author liconglong
 * @since 2022-07-09
 */
@Service
@Slf4j
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @DubboReference(group = "jike-shop",version = "1.0.0",protocol ="dubbo", check = false, cluster = "failfast",
            retries = 3, mock = "force:com.jike.shop.cloud.mock.PayServiceImpl")
    private IPayService iPayService;

    Executor executor = new ThreadPoolExecutor(5,5,0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<Runnable>(), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());



    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private RocketMQProducer rocketMQProducer;
    @Autowired
    private OrderProductMapper orderProductMapper;
    @Autowired
    private OrderProductService orderProductService;
    @Autowired
    private OrderPayInfoMapper orderPayInfoMapper;
    @Autowired
    private TransactionLogMapper transactionLogMapper;
    @Autowired
    private StateMachine<OrderStatusEnum, OrderStatusChangeEventEnum> orderStateMachine;
    @Autowired
    private StateMachinePersister<OrderStatusEnum, OrderStatusChangeEventEnum, OrderInfo> persister;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void payOrder(Long parentOrderId) {
        // 查询数据是否存在
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("parent_order_id", parentOrderId);
        OrderInfo orderInfo = orderInfoMapper.selectOne(queryWrapper);
        if(orderInfo == null){
            throw new RuntimeException("订单不存在");
        }
        // 发送事务消息
        rocketMQProducer.sendMessageInTransaction("OrderStatusUpdate", "pay", new Gson().toJson(orderInfo));
    }


    /**
     * 拆单逻辑
     * @param receiveOrder
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void splitOrder(OrderInfo receiveOrder){
        QueryWrapper<OrderInfo> orderInfoQueryWrapper = new QueryWrapper<>();
        orderInfoQueryWrapper.eq("parent_order_id", receiveOrder.getParentOrderId());
        OrderInfo queryOrder = orderInfoMapper.selectOne(orderInfoQueryWrapper);

        QueryWrapper<OrderProduct> productQueryWrapper = new QueryWrapper<>();
        productQueryWrapper.eq("parent_order_id", receiveOrder.getParentOrderId());
        List<OrderProduct> queryOrderProductList = orderProductMapper.selectList(productQueryWrapper);
        // 具体拆单逻辑，这里只以商家id为拆单逻辑
        Map<String, List<OrderProduct>> merchantMap = queryOrderProductList.stream().collect(Collectors.groupingBy(OrderProduct :: getMerchantId));
        List<OrderInfo> orderInfos = new ArrayList<>();

        OrderInfo orderInfo = null;
        SnowFlakeGenerateIdWorker snowFlakeGenerateIdWorker = new SnowFlakeGenerateIdWorker(0L, 0L);
        for (List<OrderProduct> orderProducts : merchantMap.values()){
            orderInfo = new OrderInfo();
            Long orderId = snowFlakeGenerateIdWorker.generateNextId();
            BeanUtils.copyProperties(queryOrder, orderInfo);
            orderInfo.setOrderId(orderId);
            orderInfos.add(orderInfo);
            // 忽略金额调整等业务逻辑
            for (OrderProduct orderProduct : orderProducts){
                orderProduct.setOrderId(orderId);
            }
        }
        // 删除原有订单
        orderInfoMapper.deleteById(queryOrder);
        // 批量插入订单表
        this.saveBatch(orderInfos);
        // 批量更新商品信息表
        orderProductService.updateBatchById(queryOrderProductList);
    }

    /**
     * 同步支付
     * @param orderInfo
     * @param transcationId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void syncPay(OrderInfo orderInfo, String transcationId) {
        // 查询数据库数据
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("parent_order_id", orderInfo.getParentOrderId());
        orderInfo = orderInfoMapper.selectOne(queryWrapper);
        // 使用状态机更新订单状态
        Message statusMessage = MessageBuilder.withPayload(OrderStatusChangeEventEnum.PAYED).setHeader("order", orderInfo).build();
        if (!sendEvent(statusMessage, orderInfo)) {
            log.info("线程名称：" + Thread.currentThread().getName() + " 支付失败, 状态异常，订单号：" + orderInfo.getOrderId());
        }
        // 更新订单状态
        orderInfoMapper.updateById(orderInfo);
        // 插入事务消息表
        TransactionLog transactionLog = new TransactionLog();
        transactionLog.setTransactionId(transcationId);
        transactionLog.setBusiness(String.valueOf(orderInfo.getParentOrderId()));
        transactionLog.setForeignKey(String.valueOf(orderInfo.getId()));
        transactionLogMapper.insert(transactionLog);
        // 插入支付信息表
        OrderPayInfo orderPayInfo = new OrderPayInfo();
        BeanUtils.copyProperties(orderInfo, orderPayInfo);
        orderPayInfo.setPayStatus(OrderPayStatusEnum.PAY_SUCCESS);
        orderPayInfoMapper.insert(orderPayInfo);
        // 调用收银台支付，如果支付失败，回滚事务，同时事务消息删除
        boolean payResult = iPayService.payOrder(orderInfo.getParentOrderId());
        if(!payResult){
            throw new RuntimeException("支付失败，请稍后重试");
        }
    }


    /**
     * 异步支付
     * @param orderInfo
     * @param transcationId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void asyncPay(OrderInfo orderInfo, String transcationId) {
        // 插入事务消息表
//        TransactionLog transactionLog = new TransactionLog();
//        transactionLog.setTransactionId(transcationId);
//        transactionLog.setBusiness(String.valueOf(orderInfo.getParentOrderId()));
//        transactionLog.setForeignKey(String.valueOf(orderInfo.getId()));
//        transactionLogMapper.insert(transactionLog);
//        // 插入支付信息表
//        OrderPayInfo orderPayInfo = new OrderPayInfo();
//        BeanUtils.copyProperties(orderInfo, orderPayInfo);
//        orderPayInfo.setPayStatus(OrderPayStatusEnum.WAIT_PAYMENT);
//        orderPayInfoMapper.insert(orderPayInfo);
//        executor.execute(() -> {
//            boolean payResult = iPayService.payOrder(orderInfo.getParentOrderId());
//            if(payResult){
//                // 查询数据库数据
//                QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
//                queryWrapper.eq("parent_order_id", orderInfo.getParentOrderId());
//                orderInfo = orderInfoMapper.selectOne(queryWrapper);
//                // 使用状态机更新订单状态
//                Message statusMessage = MessageBuilder.withPayload(OrderStatusChangeEventEnum.PAYED).setHeader("order", orderInfo).build();
//                if (!sendEvent(statusMessage, orderInfo)) {
//                    log.info("线程名称：" + Thread.currentThread().getName() + " 支付失败, 状态异常，订单号：" + orderInfo.getOrderId());
//                }
//                // 更新订单状态
//                orderInfoMapper.updateById(orderInfo);
//                orderPayInfoMapper.update(null);
//            }
//        });
    }


    /**
     * 模拟异步支付回查确认
     */
    @Override
    public void payFailReSend() {

    }


    /**
     * 发送订单状态转换事件
     *
     * @param message
     * @param order
     * @return
     */
    private synchronized boolean sendEvent(Message<OrderStatusChangeEventEnum> message, OrderInfo order) {
        boolean result = false;
        try {
            orderStateMachine.start();
            //尝试恢复状态机状态
            persister.restore(orderStateMachine, order);
            //添加延迟用于线程安全测试
            Thread.sleep(1000);
            result = orderStateMachine.sendEvent(message);
            //持久化状态机状态
            persister.persist(orderStateMachine, order);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            orderStateMachine.stop();
        }
        return result;
    }


}
